package com.huihe.framework.config;

import com.huihe.framework.filter.JwtAuthenticationTokenFilter;
import com.huihe.framework.handler.AuthenticationEntryPointHandler;
import com.huihe.framework.handler.LogoutSuccessHandlerImpl;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.stereotype.Component;

/**
 * Spring Security 配置
 */
@Component
@AllArgsConstructor
public class SecurityConfig {

    /**
     * 用户验证处理类
     * 注入的类为 : service.com.huihe.framework.UserDetailsServiceImpl
     */
    private UserDetailsService userDetailsService;

    /**
     * Token解析过滤器
     */
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    /**
     * 认证失败处理器
     */
    private AuthenticationEntryPointHandler authenticationEntryPointHandler;

    /**
     * 等处处理器
     */
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    /**
     * 生成 AuthenticationManager
     * @return 注册一个 AuthenticationManager 的 Bean
     */
    @Bean
    public AuthenticationManager authenticationManager(){
        // 1. 创建 DaoAuthenticationProvider , 用来实现用户身份验证
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        // 2. 指定一个实现 UserDetailsService 接口的类 (UserDetailsServiceImpl) , 并调用 loadUserByUsername 方法从数据库读取用户的信息
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        // 3. 设置密码编码器
        daoAuthenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
        // 4. 注册一个身份验证管理器
        return new ProviderManager(daoAuthenticationProvider);
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception{
        return httpSecurity
                // CSRF保护禁用
                .csrf(AbstractHttpConfigurer::disable)
                // 响应头设置
                .headers((headersConfigurer) -> headersConfigurer
                        // X-Frame-Options 不允许其他网页将本网页通过 <frame> 标签嵌入
                        .frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin))
                // 设置session
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 认证失败处理类
                .exceptionHandling(exception -> exception.authenticationEntryPoint(authenticationEntryPointHandler))
                // 添加登出过滤器,并绑定登出URI和处理器
                .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
                // 定义访问权限
                .authorizeHttpRequests((requests) -> {
                    //登录
                    requests.requestMatchers("/login").permitAll()
                            .requestMatchers("/register").permitAll()
                            .anyRequest().authenticated();
                })
                //添加Token过滤器,在身份认证的前面
                .addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
                .build();
    }
}
